package com.ericsson.epc.modules.autocheck.task;

import com.alibaba.fastjson.JSONArray;
import com.ericsson.common.mapper.JsonMapper;
import com.ericsson.common.quartz.task.ManualTask;
import com.ericsson.common.util.FileUtil;
import com.ericsson.common.util.Jdk8DateUtils;
import com.ericsson.common.util.LogFileName;
import com.ericsson.common.util.LoggerUtils;
import com.ericsson.enap.modules.autoCheck.entity.AlarmMessage;
import com.ericsson.enap.modules.autoCheck.entity.AutomqDictIms;
import com.ericsson.enap.modules.autoCheck.entity.NetAutoCheck;
import com.ericsson.enap.modules.autoCheck.entity.VisAutoCheckLog;
import com.ericsson.enap.modules.autoCheck.entity.VisAutoCheckMq;
import com.ericsson.enap.modules.autoCheck.entity.VisAutoCheckMqIdGenerator;
import com.ericsson.enap.modules.autoCheck.entity.VisExcel;
import com.ericsson.enap.modules.autoCheck.entity.VisExcelModuleDetail;
import com.ericsson.enap.modules.autoCheck.thread.EopsTemplateExecuteCmdThread;
import com.ericsson.epc.modules.autocheck.entity.EpcAutomqDict;
import com.ericsson.epc.modules.autocheck.entity.EpcNetAutoCheck;
import com.ericsson.epc.modules.autocheck.entity.EpcVisAutoCheckLog;
import com.ericsson.epc.modules.autocheck.entity.EpcVisAutoCheckMq;
import com.ericsson.epc.modules.autocheck.entity.EpcVisAutoCheckMqIdGenerator;
import com.ericsson.epc.modules.autocheck.entity.EpcVisExcel;
import com.ericsson.epc.modules.autocheck.entity.EpcVisExcelModuleDetail;
import com.ericsson.epc.modules.autocheck.service.EpcEopsTemplateScheduleService;
import com.ericsson.epc.modules.autocheck.thread.EpcEopsTemplateExecuteCmdThread;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Component;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;

@Component
@Scope("prototype")
public class EpcEopsTemplateScheduleTask  implements ManualTask {

    private Logger log = LoggerUtils.Logger(LogFileName.EpcEopsAutoCheck);

    @Autowired
    private EpcEopsTemplateScheduleService scheduleService;

    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

    @Value("${epcCollectorAddress}")
    private String collectorAddress;
    @Value("${epcTpXmlPathTxt}")
    private String TpXmlPathTxt;

    private String interval;

    private String templateTypes;

    public void setTemplateTypes(String templateTypes) {
        this.templateTypes = templateTypes;
    }

    public void setInterval(String interval) {
        this.interval = interval;
    }

    @Override
    public void execute() {
        log.info(this + "================epcEopsTemplateScheduleTask  start  interval:"+interval+"=====");
        try {
            String fetchDate = Jdk8DateUtils.now().formatDateTime("yyyy-MM-dd HH:mm:00");
            //查询3类业务模板集合
            List<EpcVisExcel> bizTemplates = scheduleService.getBizTemplates(templateTypes);

            //过滤掉非当前执行周期的模板
            List<EpcVisExcel> curIntervalTemplates = bizTemplates.stream().filter(e -> Integer.valueOf(interval).equals(e.getEcycle())).collect(Collectors.toList());
            //周期下的模板为0则退出
            if(curIntervalTemplates.isEmpty()){
                log.info("==============interval:" + interval + " template size is 0 ,task exeture end");
                return;
            }
            //将模板内相关数据写入json文件
            String ids = curIntervalTemplates.stream().map(e -> String.valueOf(e.getId())).collect(Collectors.joining(","));
            log.info("===========ids:"+ids);
            List<EpcVisExcelModuleDetail> moduleDetailList = scheduleService.getModuleDetailsByExcelIds(ids);

            System.out.println(moduleDetailList.size());

            writeToJsonFile(moduleDetailList);

            //查询需要执行的网元集合
            List<EpcNetAutoCheck> workingElements = scheduleService.getWorkingElementsByIP(collectorAddress);
            System.out.println(workingElements.size());
            Map<Long, EpcNetAutoCheck> workingElementsMap = workingElements.stream().collect(Collectors.toMap(EpcNetAutoCheck::getId, e -> e));

            Map<Long,List<EpcVisExcelModuleDetail>> netExecuteTemplates = rebuildNetAndTemplate(workingElements,moduleDetailList);

            CountDownLatch latch = new CountDownLatch(netExecuteTemplates.size());
            log.info("initial = " + interval + "==========CountDownLatch size:" + netExecuteTemplates.size());
            for (Map.Entry<Long, List<EpcVisExcelModuleDetail>> entry : netExecuteTemplates.entrySet()) {
                EpcEopsTemplateExecuteCmdThread executeCmdThread = new EpcEopsTemplateExecuteCmdThread(workingElementsMap.get(entry.getKey()),entry.getValue(),scheduleService,latch,fetchDate,log,TpXmlPathTxt);
                Thread t = new Thread(executeCmdThread);
                t.start();
            }
            latch.await();

            sendAlarmToMq(fetchDate,workingElements);
            log.info("===== all sub thread run end! =====");
            log.info("initial = " + interval + "================= task run end  ========");
            //定时任务执行后开始新线程查询最新告警，并且发送mq
        } catch (Exception e) {
            log.error("error===="+ e.getMessage()+"====",e);
        }
    }

    public void sendAlarmToMq(String fetchDate,List<EpcNetAutoCheck> workingElements) {

        new Thread(new Runnable() {
            @Override
            public void run() {
                log.info("==============sync mq start=================");
                Map<Integer, EpcAutomqDict> dictMap = scheduleService.getEpcAutomqDictList().stream().collect(Collectors.toMap(EpcAutomqDict::getVisexcelId, automqDict -> automqDict));
                Map<String, EpcVisAutoCheckMq> autocheckmqMap = scheduleService.getAutoCheckMqList().stream().collect(Collectors.toMap(k -> k.getExcelId()+"-"+k.getNetId(), visAutoCheckMq -> visAutoCheckMq));
                Map<String, EpcVisAutoCheckLog> autoCheckLogMap = scheduleService.getCurrentTimeAlarm().stream().collect(Collectors.toMap(k -> k.getExcelId()+"-"+k.getNetId(), visAutoCheckLog -> visAutoCheckLog));
                List<EpcVisExcel> bizTemplates = scheduleService.getBizTemplates("'ALARMTEM'");
                Map<Integer, EpcVisExcel> tempMap = bizTemplates.stream().collect(Collectors.toMap(EpcVisExcel::getId, visExcel -> visExcel));
                int netCount = workingElements.size();  //需要采集网元个数
                Map<Long,EpcNetAutoCheck> netMap = scheduleService.getWorkingElementsByIP(collectorAddress).stream().collect(Collectors.toMap(EpcNetAutoCheck::getId, net -> net));
                Map<Long,EpcNetAutoCheck> allNetMap = scheduleService.getWorkingElementsByIP(null).stream().collect(Collectors.toMap(EpcNetAutoCheck::getId, net -> net));
                try {
                    for(String logKey : autoCheckLogMap.keySet()) {
                        EpcVisAutoCheckMq mq = autocheckmqMap.get(logKey);
                        if(mq == null &&  netCount>0) {
                            //一条新的告警，发送mq  AlarmStatus=1, t_autocheck_mq 插入一条数据
                            String[] logKeyArr = logKey.split("-");
                            if(null != logKeyArr && logKeyArr.length == 2) {
                                EpcAutomqDict dict = dictMap.get(Integer.parseInt(logKeyArr[0]));
                                //VisExcel excel = tempMap.get(Integer.parseInt(logKeyArr[0]));
                                if(dict != null) {

                                    EpcNetAutoCheck net = netMap.get(Long.valueOf(logKeyArr[1]));

                                    EpcVisAutoCheckLog checklog = autoCheckLogMap.get(logKey);
                                    //获取该类型最大编号
                                    EpcVisAutoCheckMqIdGenerator idGen = scheduleService.getIdByType(checklog.getNetType());
                                    long maxid = idGen.getIdValue() + 1;
                                    idGen.setIdValue(maxid);
                                    String alarmId = dict.getAlarmUniqueId()+"-"+maxid;

                                    String subObject = net.getFname();

                                    String message = createMqMessage(alarmId,"11000","1",String.valueOf(net.getId()),net.getFname(),subObject,dict);
                                    //sendAlarm(message);
                                    mq = new EpcVisAutoCheckMq();
                                    mq.setNetId(logKeyArr[1]);
                                    mq.setExcelId(Integer.parseInt(logKeyArr[0]));
                                    mq.setCreateTime(fetchDate);
                                    mq.setStatus(1);
                                    mq.setCreateAlarmMsg(message);
                                    mq.setNetType(checklog.getNetType());
                                    mq.setAlarmId(alarmId);
                                    scheduleService.insertAutoCheckMq(mq);
                                    //更新最大序号
                                    scheduleService.updateIdValue(idGen);
                                    log.info("==============netid:"+mq.getNetId()+"    excelid:"+mq.getExcelId()+"   AlarmUniqueId："+alarmId+"======产生告警===========");
                                } else {
                                    log.error("=================没有配置"+logKeyArr[0]+"========================");
                                }

                            }
                        }
                    }

                    for(String mqkey: autocheckmqMap.keySet()) {
                        EpcVisAutoCheckLog checklog = autoCheckLogMap.get(mqkey);
                        if(checklog == null || netCount<=0) {  // 如果取消所有网元采集
                            //消除告警，发送mq  AlarmStatus=0  , 修改t_autocheck_mq update_time字段 和status字段
                            String[] mqKeyArr = mqkey.split("-");
                            if(null != mqKeyArr && mqKeyArr.length == 2) {
                                EpcAutomqDict dict = dictMap.get(Integer.parseInt(mqKeyArr[0]));
                                EpcVisExcel excel = tempMap.get(Integer.parseInt(mqKeyArr[0]));
                                if(dict != null) {

                                    EpcNetAutoCheck net = netMap.get(Integer.valueOf(mqKeyArr[1]));
                                    if(net == null) {
                                        net = allNetMap.get(Integer.valueOf(mqKeyArr[1]));
                                    }
                                    //发送mq
                                    EpcVisAutoCheckMq mq = autocheckmqMap.get(mqkey);
                                    AlarmMessage am = (AlarmMessage) JsonMapper.fromJsonString(mq.getCreateAlarmMsg(),AlarmMessage.class);
                                    System.out.println(am.getObjectName());
                                    String message = createMqMessage(mq.getAlarmId(),"11001","0",String.valueOf(net.getId()),net.getFname(),am.getSubObjectUID(),dict);
                                   //sendAlarm(message);
                                    //修改数据库表
                                    mq.setUpdateTime(fetchDate);
                                    mq.setStatus(0);
                                    mq.setCancelAlarmMsg(message);
                                    scheduleService.updateAutoCheckMq(mq);
                                    log.info("==============netid:"+mq.getNetId()+"    excelid:"+mq.getExcelId()+"  AlarmUniqueId："+mq.getAlarmId()+"======消除告警===========");

                                }else {
                                    log.error("=================没有配置"+mqKeyArr[0]+"========================");
                                }
                            }
                        }
                    }
                } catch (Exception e) {
                    log.error("error===="+ e.getMessage()+"====",e);
                }

                log.info("==============sync mq end=================");
            }
        }).start();


    }

    private void writeToJsonFile(List<EpcVisExcelModuleDetail> moduleDetailList) {

        Map<String,List<Object>> jsonMap = new HashMap<>();
        for(EpcVisExcelModuleDetail moduleDetail : moduleDetailList){
            Integer excelId = moduleDetail.getExcelId();
            Integer moduleId = moduleDetail.getModuleId();
            if(jsonMap.containsKey(excelId+"_"+moduleId)){
                jsonMap.get(excelId+"_"+moduleId).add(moduleDetail);
            }else{
                List<Object> jsonList = new ArrayList<>();
                jsonList.add(moduleDetail);
                jsonMap.put(excelId+"_"+moduleId,jsonList);
            }
        }

        for(Map.Entry<String,List<Object>> entry : jsonMap.entrySet()){
            File file = new File(TpXmlPathTxt + File.separator + entry.getKey()+".txt");
            file.getParentFile().mkdirs();
            FileUtil.writeToFile(file.getAbsolutePath(), JSONArray.toJSONString(entry.getValue()),false);
        }
    }

    private Map<Long,List<EpcVisExcelModuleDetail>> rebuildNetAndTemplate(List<EpcNetAutoCheck> workingElements, List<EpcVisExcelModuleDetail> moduleDetailList) {

        //过滤相同模块的元素
        List<EpcVisExcelModuleDetail> subModuleDetailList = new ArrayList<>();
        List<String> excelModuleIds = new ArrayList<>();
        for(EpcVisExcelModuleDetail item : moduleDetailList){
            if(!excelModuleIds.contains(item.getExcelId()+"_"+item.getModuleId())){
                subModuleDetailList.add(item);
                excelModuleIds.add(item.getExcelId()+"_"+item.getModuleId());
            }
        }

        Map<Long,List<EpcVisExcelModuleDetail>> netExecuteTemplates = new HashMap<>();
        for(EpcVisExcelModuleDetail moduleDetail : subModuleDetailList){
            for(EpcNetAutoCheck net : workingElements){
                if(net.getType().equals(moduleDetail.getType())){
                    if(netExecuteTemplates.containsKey(net.getId())){
                        netExecuteTemplates.get(net.getId()).add(moduleDetail);
                    }else{
                        List<EpcVisExcelModuleDetail> moduleDetails = new ArrayList<>();
                        moduleDetails.add(moduleDetail);
                        netExecuteTemplates.put(net.getId(),moduleDetails);
                    }
                }
            }
        }
        return netExecuteTemplates;
    }

    public String createMqMessage(String alarmId,String subMessageType,String alarmStatus,String objectUID,String objectName,String subObjectUID, EpcAutomqDict dict) {
        String alarmSeq = Jdk8DateUtils.now().formatDateTime("yyyyMMddHHmmss");
        String eventTime = Jdk8DateUtils.now().formatDateTime("yyyy-MM-dd HH:mm:ss");
        AlarmMessage message = new AlarmMessage();
        message.setSystemId(dict.getSystemId()); //三方系统ID
        message.setMessageType(dict.getMessageType()); //消息分类-一级分类
        message.setSubMessageType(subMessageType); //消息分类-二级分类
        message.setAlarmTitle(dict.getAlarmTitle()); //告警标题
        message.setAlarmStatus(alarmStatus); //告警状态 1：活动告警；0：清除告警
        message.setAlarmId(alarmId); //告警ID  产生告警与消除告警ID相同
        message.setAlarmSeq(alarmSeq);//告警上报的消息序号 ,每产生一条告警包括消除告警，会产生唯一序号
        message.setAlarmType(dict.getAlarmType()); //告警类型
        message.setOrigSeverity(dict.getOrigSeverity()); //原始级别
        message.setEventTime(eventTime);  //告警发生时间
        message.setSpecificProblemID(dict.getSpecificProblemID()); //告警问题原因ID。厂家告警ID
        message.setSpecificProblem(dict.getSpecificProblem()); //告警问题原因
        message.setObjectType(dict.getObjectType()); //设备类型
        message.setObjectUID(objectName); //告警定位对象UID
        message.setObjectName(objectName);  //网元名

		/*String subObjectType = "";
		if(!"".equals(subObjectUID)) {
			if(subObjectUID.contains("PL")) {
				subObjectType = "PL板卡";
			} else if(subObjectUID.contains("SC")) {
				subObjectType = "SC板卡";
			}
		}*/
        message.setSubObjectUID(objectName); //告警定位子对象UID
        message.setSubObjectType(dict.getObjectType());  //告警对象类型
        message.setSubObjectName(objectName); //告警定位子对象啊名称

        message.setVendorName(dict.getVendorName()); //厂家
        message.setProvince(dict.getProvince()); //省份
        message.setCity(dict.getCity()); //地市
        message.setAddInfo("");//告警定位信息 为空可以显示告警正文
        return JsonMapper.toJsonString(message);
    }

    public void sendAlarm(String alarmMessage) {
        kafkaTemplate.send("ericsson_expert_system", alarmMessage);
    }

}
